"""
- numpy的学习 - （ numpy-1.19.2）

"""

import math
import numpy as np


def ndarray_usage():
    """
    ndarray 的简单使用
    :return:
    """
    a = np.arange(10)  # 获取一个 numpy.ndarray 对象
    print(a)
    print(type(a))

    b = [3, 4, 9]
    # 获取每个元素的开平方根
    result = [math.sqrt(i) for i in b]  # 使用math
    print(result)
    # 对ndarray对象类型进行向量处理
    result2 = np.sqrt(b)
    print(result2)


# 数组的创建
def array_func_usage():
    # 使用arange 创建数组 range(start, end, step)  [start, end)
    a = np.arange(1, 11)  # 1 - 10
    b = np.arange(0, 10, 2)  # 0-10的偶数
    c = np.arange(0, 10, 2, dtype=float)  # 设置dtype
    print('nddim：', a.ndim, b.ndim, c.ndim)
    print('shape：', a.shape, b.shape, c.shape)
    print('元素类型 dtype：', a.dtype, b.dtype, c.dtype)
    print('元素的总个数 size：', a.size, b.size, c.size)
    print('每个元素的内存 itemsize：', a.itemsize, b.itemsize, c.itemsize)

    print('-' * 30, 'np.random.random')

    # 使用random 创建数组 - 0-1小数
    a = np.random.random(size=5)  # 一维数组
    print(a, type(a))
    b = np.random.random(size=(3, 4))  # 二维数组
    print(b, type(b))
    c = np.random.random(size=(2, 3, 4))  # 三维数组
    print(c, type(c))
    print('-' * 30, 'np.random.randint')

    # 使用random 创建数组 - 整数
    a = np.random.randint(5, size=10)  # 0-5 之间的1维数组
    print(a, type(a), a.dtype)
    a1 = np.random.randint(5, size=10, dtype=np.int64)  # 0-5 之间的1维数组
    print(a1, type(a1), a1.dtype)  # 定义dtype
    b = np.random.randint(5, 11, size=(4, 3))
    print(b, type(b))
    c = np.random.randint(5, 11, size=(2, 3, 4))  # 三维数组
    print(c, type(c))

    print('-' * 30, 'np.random.randn')
    # 使用random 创建数组 - 符合正态分布(期望为0，方差为1)
    a = np.random.randn(5)  # 4个1维数组 ，
    print(a, type(a))
    b = np.random.randn(2, 3)
    print(b, type(b))
    # 指定期望和方差的正态分布
    a = np.random.normal(size=5)  # 默认期望为0，方差为1
    print(a, type(a))
    b = np.random.normal(loc=1, scale=2, size=5)
    print(b, type(b))

    print('-' * 30, 'np.zeros')
    a = np.zeros(5)  # 默认float
    print(a, type(a))
    b = np.zeros(5, dtype=int)
    print(b, type(b))
    c = np.zeros((2, 3))
    print(c, type(c))

    print('-' * 30, 'np.ones')
    a = np.ones(5)
    print(a, type(a))
    b = np.ones(5, dtype=int)
    print(b, type(b))
    c = np.ones((2, 3))
    print(c, type(c))

    print('-' * 30, 'np.empty')  # 未初始化的数组
    a1 = np.empty(5)
    print(a1, type(a1))
    b1 = np.empty(5, dtype=int)
    print(b1, type(b1))
    c1 = np.empty((2, 3))
    print(c1, type(c1))

    print('-' * 30, 'np.linspace 等差数列')
    a = np.linspace(1, 10, 10)  # 等差数列 在 1，10之间生成10个数,包括10
    print(a, type(a))
    b = np.linspace(10, 1, 5)
    print(b, type(b))

    b = np.linspace(1, 10, 10, endpoint=False)
    print(b, type(b))

    print('-' * 30, 'np.logspace 等比数列')
    a = np.logspace(0, 9, 10)
    print(a, type(a))

    b = np.logspace(0, 9, 10, base=2)
    print(b, type(b))


# 切片 / 索引
def split_index():
    a = np.arange(10)  # 获取一个 numpy.ndarray 对象
    print(a)
    print('第5个:', a[5])

    print(('最后一个元素', a[-1]))
    print(('倒数第3个元素', a[-3]))
    # 切片的正向索引 [start：stop：step]
    print(('所有的元素', a[:]))
    print(('索引3开始：', a[3:]))
    print(('索引3-5:', a[3:5]))
    print(('索引1-6，步长2:', a[1:7:2]))
    # 切片的负向索引
    print(('倒着所有原色:', a[::-1]))  # 反向获取
    print(('索引6-1，步长2:', a[-1:0:-2]))

    print('-' * 30, '二维数组的切片')
    x = np.arange(1, 21)
    b = x.reshape(4, 5)
    print(b)
    print(b[1])
    print(b[1][2])
    # 行，列的切片  [start：stop：step]
    print('所有行，所有列:\r\n', b[:, :])
    print('所有行，第2列:\r\n', b[:, 1])
    print('所有行，第1,2列:\r\n', b[:, 0:2])
    print('奇数行，所有列:\r\n', b[::2, :])
    print('奇数行，所有列:\r\n', b[::2, 0:2])

    # 坐标获取
    print('行2列3的元素:', b[1, 2])
    print('2个元素:', b[1, 2], b[1, 0])
    print('2个元素组成array:', np.array([b[1, 2], b[1, 0]]))
    print('2个元素组成array:', b[(1, 2), (2, 0)])  # 获得的是 (1,2),(2,0)

    # 负索引
    print('最后一行:\r\n', b[-1])
    print('行倒叙:\r\n', b[::-1])
    print('行,列倒叙:\r\n', b[::-1, ::-1])


def array_copy_usage():
    a = np.arange(1, 21).reshape(4, 5)
    # 1,2行，1，2列
    sub_a = a[:2, :2]  # 切片只是浅拷贝
    print(sub_a)
    sub_a[0][0] = 100
    print(sub_a)
    print(a)
    # 利用numpy的copy方法
    sub_aa = np.copy(a[:2, :2])  # 深拷贝
    sub_aa[0][0] = 200
    print(sub_aa)
    print(a)


def change_shape():
    # 使用reshape
    a = np.arange(1, 25).reshape(4, 6)
    print(a)
    b = np.arange(1, 25).reshape(3, 8)
    print(b)
    c = np.arange(1, 25).reshape(2, 3, 4)
    print(c)
    d = np.reshape(np.arange(1, 25), (4, 6))
    print(d)
    # 多维变一维
    ad = d.reshape(24)
    print(ad)
    ac = c.reshape(-1)  # 所有的元素组合变成一维数组
    print(ad)

    # ravel 多维变一维
    print(d.ravel())
    print(d.flatten())
    print(d.flatten())


# 数组的拼接
def stack_usage():
    # 水平拼接 行数不变
    # 垂直拼接 列数不变
    a = np.arange(1, 7).reshape(2, 3)
    b = np.arange(11, 17).reshape(2, 3)
    print('水平拼接', np.hstack((a, b)))
    print('垂直拼接 ', np.vstack((a, b)))
    # concatenate 指定轴
    print('concatenate 默认垂直 ', np.concatenate((a, b), ))
    print('concatenate 定义水平 ', np.concatenate((a, b), axis=1))
    # concatenate 3 维数组的拼接
    a = np.arange(1, 25).reshape(2, 3, 4)
    b = np.arange(101, 125).reshape(2, 3, 4)
    print('concatenate 第0维 默认 ', np.concatenate((a, b)))
    print('concatenate 第1维: ', np.concatenate((a, b), axis=1))
    print('concatenate 第2维 ', np.concatenate((a, b), axis=2))


# 数组的分割
def split_usage():
    x = np.arange(1, 9)
    # 数组要刚好能平分，否则抛异常ValueError
    print(np.split(x, 4))
    print(np.split(x, [4, 6]))  # 按位置分割
    # 二维数组的分割
    a = np.arange(1, 17).reshape(4, 4)
    print(a)
    r, w = np.split(a, 2)
    print('-' * 30)
    print(r)
    print('-' * 30)
    print(w)
    a1, a2, a3 = np.split(a, [2, 3])
    print('-' * 30)
    print(a1)
    print('-' * 30)
    print(a2)
    print('-' * 30)
    print(a3)
    r, w = np.split(a, 2, axis=1)
    print('-' * 30)
    print(r)
    print('-' * 30)
    print(w)


# 数组的转置
def transpose():
    a = np.arange(1, 17).reshape(4, 4)
    print(a)
    print(a.transpose())
    print('-' * 30)
    print(a.T)
    print('-' * 30)
    print(np.transpose(a))
    print('-' * 30)
    # 3维数组的转置
    a = np.arange(1, 25).reshape(2, 3, 4)
    print(a.transpose())
    print('-' * 30)

    x = np.ones((1, 2, 3))
    print(np.transpose(x, (1, 2, 0)))


# 算术函数
def math_func():
    a = np.arange(1, 10).reshape(3, 3)
    b = np.array([10, 10, 10])
    print('-' * 30, '加法')
    print(np.add(a, b))
    print(a + b)
    print('-' * 30, '减法')
    print(np.add(a, b))
    print(a + b)

    # out参数的使用
    y = np.empty((3, 3))
    np.multiply(a, 10, out=y)  # 返回结果到维度一样的对象中
    print(y)

    # 数学函数
    c = np.array([0, 30, 60, 90])
    print(np.sin(c))
    c = np.array([0.11, 30.4362, 60.87, 90.4352])
    print('around', np.around(c, 2))  # 小数点位
    print('round', np.round(c))  # int
    print('ceil', np.ceil(c))
    print('floor', np.floor(c))

    # 聚合函数 sum， prod, mean, std, var, mdian, power, sqrt, min, max, argmin, argmax , inf, exp, log
    a = np.arange(1, 10).reshape(3, 3)
    print(np.power(a, 2))  # 幂次方

    y = np.zeros((5, 5))
    np.power(a, 2, out=y[:3, :3])  #
    print('out参数的使用', y)

    a = np.array([3, 4, 4, 5, 2, 4, 6, 5, 9])
    print('中位数', np.median(a))  # 中位数
    print('平均数', np.mean(a))
    print('最小值', np.min(a))
    print('最大值', np.max(a))
    print('Shape:', np.shape(a))

    # axis指定轴
    a = np.arange(1, 13).reshape(2, 3, 2)
    print(a)
    print('垂直方向中位数', np.median(a, axis=0))  # 返回一个数组
    print('水平方向中位数', np.median(a, axis=1))

    # 二维数组 求平局
    print('垂直方向 平均数', np.mean(a, axis=0))  # 返回一个数组
    print('水平方向 平均数', np.mean(a, axis=1))


if __name__ == '__main__':
    # ndarray_usage()
    # array_func_usage()
    # split_index()
    # array_copy_usage()
    # change_shape()
    # stack_usage()
    # split_usage()
    # transpose()
    math_func()
